package co.edu.poli.ficb.agl.automatable.gui;

import java.awt.Component;
import java.awt.Dimension;
import java.awt.Shape;
import java.awt.geom.AffineTransform;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Point2D;

import co.edu.poli.ficb.agl.automatable.graph.Arista;
import co.edu.poli.ficb.agl.automatable.graph.Vertice;
import edu.uci.ics.jung.algorithms.layout.Layout;
import edu.uci.ics.jung.graph.Graph;
import edu.uci.ics.jung.graph.util.Context;
import edu.uci.ics.jung.graph.util.Pair;
import edu.uci.ics.jung.visualization.Layer;
import edu.uci.ics.jung.visualization.RenderContext;
import edu.uci.ics.jung.visualization.renderers.BasicEdgeLabelRenderer;
import edu.uci.ics.jung.visualization.transform.shape.GraphicsDecorator;

public class PA2BasicEdgeLabelRenderer extends
		BasicEdgeLabelRenderer<Vertice, Arista> {
	
	private PA2LabelConfiguration labelConfiguration;
	
	public PA2BasicEdgeLabelRenderer(PA2LabelConfiguration labelConfiguration) {
		this.labelConfiguration = labelConfiguration;
	}

	@Override
	public void labelEdge(
			RenderContext<Vertice, Arista> rc,
			Layout<Vertice, Arista> layout,
			Arista e, String label) {
		
		//System.out.println("santi!");
		
		if (label == null || label.length() == 0)
			return;

		Graph<Vertice, Arista> graph = layout.getGraph();
		// don't draw edge if either incident vertex is not drawn
		Pair<Vertice> endpoints = graph.getEndpoints(e);
		Vertice v1 = endpoints.getFirst();
		Vertice v2 = endpoints.getSecond();
		
		if (!rc.getEdgeIncludePredicate().evaluate(
				Context.<Graph<Vertice, Arista>, Arista> getInstance(graph, e)))
			return;

		if (!rc.getVertexIncludePredicate().evaluate(
				Context.<Graph<Vertice, Arista>, Vertice> getInstance(graph, v1))
				|| !rc.getVertexIncludePredicate().evaluate(
						Context.<Graph<Vertice, Arista>, Vertice> getInstance(graph, v2)))
			return;

		Point2D p1 = layout.transform(v1);
		Point2D p2 = layout.transform(v2);
		p1 = rc.getMultiLayerTransformer().transform(Layer.LAYOUT, p1);
		p2 = rc.getMultiLayerTransformer().transform(Layer.LAYOUT, p2);
		float x1 = (float) p1.getX();
		float y1 = (float) p1.getY();
		float x2 = (float) p2.getX();
		float y2 = (float) p2.getY();

		GraphicsDecorator g = rc.getGraphicsContext();
		float distX = x2 - x1;
		float distY = y2 - y1;
		double totalLength = Math.sqrt(distX * distX + distY * distY);

		double closeness = rc.getEdgeLabelClosenessTransformer()
				.transform(Context.<Graph<Vertice, Arista>, Arista> getInstance(graph, e))
				.doubleValue();
		
		/*
		if (v1.equals(v2)) {
			//TODO
			closeness = 50d;
		}
		*/
		//System.out.println(v1+" - "+v2);
		//System.out.println("closeness:"+closeness);

		int posX = (int) (x1 + (closeness) * distX);
		int posY = (int) (y1 + (closeness) * distY);

		int xDisplacement = (int) (rc.getLabelOffset() * (distY / totalLength));
		int yDisplacement = (int) (rc.getLabelOffset() * (-distX / totalLength));

		Component component = prepareRenderer(rc, rc.getEdgeLabelRenderer(),
				label, rc.getPickedEdgeState().isPicked(e), e);
		
		//component.setBackground(Color.red);
		//component.setPreferredSize(new Dimension(component.getWidth(), 50));

		Dimension d = component.getPreferredSize();

		Shape edgeShape = rc.getEdgeShapeTransformer().transform(
				Context.<Graph<Vertice, Arista>, Arista> getInstance(graph, e));

		double parallelOffset = 1;

		parallelOffset += rc.getParallelEdgeIndexFunction().getIndex(graph, e);

		parallelOffset *= d.height;
		if (edgeShape instanceof Ellipse2D) {
			parallelOffset += edgeShape.getBounds().getHeight();
			parallelOffset = -parallelOffset;
		}
		
		//System.out.println("parallelOffset:"+parallelOffset);

		AffineTransform old = g.getTransform();
		AffineTransform xform = new AffineTransform(old);
		xform.translate(posX + xDisplacement, posY + yDisplacement);
		double dx = x2 - x1;
		double dy = y2 - y1;
		if (rc.getEdgeLabelRenderer().isRotateEdgeLabels()) {
			double theta = Math.atan2(dy, dx);
			if (dx < 0) {
				theta += Math.PI;
			}
			xform.rotate(theta);
		}
		if (dx < 0) {
			parallelOffset = -parallelOffset;
		}
		
		// TODO mejorar esto:
		if (v1.equals(v2)) {
			//parallelOffset = Math.abs(parallelOffset);
			parallelOffset = -70;
		}

		xform.translate(-d.width / 2, -(d.height / 2 - parallelOffset));
		g.setTransform(xform);
		g.draw(component, rc.getRendererPane(), 0, 0, d.width, d.height, true);
		
		//System.out.println("posX+xDisplacement:"+(posX+xDisplacement)+", posY+yDisplacement"+(posY+yDisplacement));
		
		// DS
		//labelConfiguration.savePosition(e, posX+xDisplacement, posY+yDisplacement);
		labelConfiguration.savePosition(e, (int)xform.getTranslateX(), (int)xform.getTranslateY());

		g.setTransform(old);
	}
}
	